package com.request.service.impl.shop.sj;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.request.common.constants.RedisConstant;
import com.request.common.enums.SjErrorCodeEnum;
import com.request.common.enums.SjOrderTypeEnum;
import com.request.common.utils.HttpUtils;
import com.request.common.webfacade.bo.SjShopOrderNoBO;
import com.request.entity.PhoneOrderAvailable;
import com.request.entity.PhoneOrderWaitPush;
import com.request.entity.out.PushOrderForSj;
import com.request.service.PushOrderProcessor;
import com.request.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Description:
 * Create DateTime: 2020/7/24 17:19
 *
 * 

 */
@Slf4j
@Service
public class SjPushOrderProcessor implements PushOrderProcessor {

    @Resource
    private RedisService redisService;

    @Resource
    private ThreadPoolExecutor handlerOrderExecutor;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public void sendRequest(PhoneOrderWaitPush phoneOrderWaitPush) {
        handlerOrderExecutor.execute(() -> executeSend(phoneOrderWaitPush));
    }

    private void executeSend(PhoneOrderWaitPush phoneOrderWaitPush) {
        if (phoneOrderWaitPush == null) {
            return;
        }
        PhoneOrderAvailable phoneOrderAvailable = phoneOrderWaitPush.getPhoneOrderAvailable();
        PushOrderForSj pushOrderForSj = new PushOrderForSj();

        String result = null;
        try {
            pushOrderForSj.setMerchantId(Integer.valueOf(phoneOrderWaitPush.getAppId()));
            pushOrderForSj.setOrderType(SjOrderTypeEnum.FAST.getCode());
            pushOrderForSj.setMobile(phoneOrderAvailable.getPhoneNum());
            pushOrderForSj.setTradeNoThird(phoneOrderAvailable.getPlatformOrderNo());
            pushOrderForSj.setAmount(phoneOrderAvailable.getOrderPrice().setScale(2).toPlainString());
            pushOrderForSj.setNotifyUrl(phoneOrderWaitPush.getShopCallbackSite());

            StringBuilder sb = new StringBuilder();
            sb.append(pushOrderForSj.getMerchantId())
                    .append(pushOrderForSj.getOrderType())
                    .append(pushOrderForSj.getMobile())
                    .append(pushOrderForSj.getTradeNoThird())
                    .append(pushOrderForSj.getAmount())
                    .append(pushOrderForSj.getNotifyUrl())
                    .append(phoneOrderWaitPush.getAppKey());

            String signStr = SecureUtil.md5(sb.toString());
            pushOrderForSj.setSignstr(signStr);

            log.info("【SJ】【推单】请求参数为：{}", pushOrderForSj);

            try {
                result = sendRequestForPushOrder(phoneOrderWaitPush.getPushSite(), pushOrderForSj);
            } catch (Exception e) {
                savePushOrderForException(phoneOrderWaitPush);
                savePushOrderForSuccess(phoneOrderAvailable.getPlatformOrderNo());
                log.info("【SJ】【推单】发送请求出现异常：", e);
                return;
            }
            log.info("【SJ】【推单】订单号为：{}, 结果:{}", phoneOrderAvailable.getPlatformOrderNo(), result);

            JSONObject json = JSONObject.parseObject(result);
            Integer code = json.getInteger("code");

            if (SjErrorCodeEnum.SUCCESS.getCode() != code) {
                String msg = json.getString("msg");
                log.info("【SJ】【推单】响应状态标识位下单失败,响应状态码为：{}， 详细信息为：{}", code, msg);
                savePushOrderForFailed(phoneOrderWaitPush);
                return;
            }

            savePushOrderForSuccess(phoneOrderAvailable.getPlatformOrderNo());

            String shopOrderNo = json.getJSONObject("body").getString("tradeNoSelf");
            savePushOrderForSuccessWithShopOrderNo(phoneOrderAvailable.getPlatformOrderNo(), shopOrderNo);
        } catch (Exception e) {
            savePushOrderForSuccess(phoneOrderAvailable.getPlatformOrderNo());
            log.error("【SJ】【推送订单】推送订单失败，待推送订单信息为：{}, 请求参数为：{}, 商户响应结果为：{}, 详细错误信息为：",
                    phoneOrderWaitPush, pushOrderForSj, result, e);
        }
    }


    /**
     * 发送Http请求
     *
     * @param url            请求路径
     * @param pushOrderForSj 参数
     * @return 响应结果
     */
    private String sendRequestForPushOrder(String url, PushOrderForSj pushOrderForSj) {
        Map<String, Object> paramMap = BeanUtil.beanToMap(pushOrderForSj);
        return HttpUtils.doPost(url, paramMap);
    }

    /**
     * 放入失败队列
     */
    private void savePushOrderForFailed(PhoneOrderWaitPush phoneOrderWaitPush) {
        redisService.lPush(RedisConstant.PUSH_ORDER_WAIT_PUSH_RECORD, JSON.toJSONString(phoneOrderWaitPush));
    }

    /**
     * 放入成功队列
     */
    private void savePushOrderForSuccess(String platformOrderNo) {
        redisTemplate.opsForValue().set(RedisConstant.PUSH_ORDER_WAIT_PUSH_SUCCESS + platformOrderNo, platformOrderNo, 30, TimeUnit.MINUTES);
    }

    /**
     * 放入发送出现异常的队列
     */
    private void savePushOrderForException(PhoneOrderWaitPush phoneOrderWaitPush) {
        redisService.lPush(RedisConstant.PUSH_ORDER_WAIT_PUSH_EXCEPTION, JSON.toJSONString(phoneOrderWaitPush));
    }

    /**
     * 放入SJ专属下单成功队列
     *
     * @param platformOrderNo 平台订单号
     * @param shopOrderNo     商户订单号
     */
    private void savePushOrderForSuccessWithShopOrderNo(String platformOrderNo, String shopOrderNo) {
        SjShopOrderNoBO sjShopOrderNoBO = new SjShopOrderNoBO();
        sjShopOrderNoBO.setPlatformOrderNo(platformOrderNo);
        sjShopOrderNoBO.setShopOrderNo(shopOrderNo);
        redisService.lPush(RedisConstant.PUSH_ORDER_SJ_SUCCESS_WITH_SHOP_ORDER_NO, JSON.toJSONString(sjShopOrderNoBO));
    }
}
